package com.zeroz.zookeeper.curator;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.CuratorWatcher;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.data.Stat;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * Apache Curator框架基本操作示例
 * Curator是更易用的ZooKeeper客户端API
 */
public class CuratorBasicExample {
    private static final String CONNECT_STRING = "localhost:2181,localhost:2182,localhost:2183";
    private static final int SESSION_TIMEOUT = 5000;
    private static final int CONNECTION_TIMEOUT = 5000;
    private CuratorFramework client;
    
    /**
     * 连接到ZooKeeper
     */
    public void connect() {
        // 创建重试策略
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        
        // 创建Curator客户端
        client = CuratorFrameworkFactory.builder()
                .connectString(CONNECT_STRING)
                .sessionTimeoutMs(SESSION_TIMEOUT)
                .connectionTimeoutMs(CONNECTION_TIMEOUT)
                .retryPolicy(retryPolicy)
                .namespace("curator") // 添加命名空间，所有操作都会在/curator路径下
                .build();
        
        // 启动客户端
        client.start();
        System.out.println("Curator客户端已启动");
    }
    
    /**
     * 创建节点
     */
    public String createNode(String path, String data) throws Exception {
        return client.create()
                .creatingParentsIfNeeded() // 如果父节点不存在则创建
                .withMode(CreateMode.PERSISTENT)
                .forPath(path, data.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * 创建临时节点
     */
    public String createEphemeralNode(String path, String data) throws Exception {
        return client.create()
                .creatingParentsIfNeeded()
                .withMode(CreateMode.EPHEMERAL)
                .forPath(path, data.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * 检查节点是否存在
     */
    public boolean checkExists(String path) throws Exception {
        Stat stat = client.checkExists().forPath(path);
        return stat != null;
    }
    
    /**
     * 获取节点数据
     */
    public String getData(String path) throws Exception {
        byte[] bytes = client.getData().forPath(path);
        return new String(bytes, StandardCharsets.UTF_8);
    }
    
    /**
     * 设置节点数据
     */
    public Stat setData(String path, String data) throws Exception {
        return client.setData().forPath(path, data.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * 获取子节点列表
     */
    public List<String> getChildren(String path) throws Exception {
        return client.getChildren().forPath(path);
    }
    
    /**
     * 删除节点
     */
    public void deleteNode(String path) throws Exception {
        client.delete()
                .guaranteed() // 保证删除
                .deletingChildrenIfNeeded() // 级联删除子节点
                .forPath(path);
    }
    
    /**
     * 添加节点监听器
     */
    public void watchNode(String path) throws Exception {
        // 创建一个CuratorWatcher
        CuratorWatcher watcher = new CuratorWatcher() {
            @Override
            public void process(WatchedEvent event) throws Exception {
                System.out.println("触发监听事件: " + event);
                
                // 获取新数据
                if (event.getType().name().equals("NodeDataChanged")) {
                    byte[] data = client.getData().forPath(path);
                    System.out.println("数据已更新: " + new String(data, StandardCharsets.UTF_8));
                    
                    // 重新添加监听 (Curator不会自动重新添加)
                    watchNode(path);
                }
            }
        };
        
        // 添加监听
        client.getData().usingWatcher(watcher).forPath(path);
        System.out.println("已添加监听器: " + path);
    }
    
    /**
     * 关闭连接
     */
    public void close() {
        if (client != null) {
            client.close();
            System.out.println("Curator客户端已关闭");
        }
    }
    
    public static void main(String[] args) {
        CuratorBasicExample example = new CuratorBasicExample();
        
        try {
            // 连接ZooKeeper
            example.connect();
            
            // 创建节点 (注意：使用了namespace，实际路径是/curator/example)
            String path = "/example";
            if (!example.checkExists(path)) {
                String createdPath = example.createNode(path, "Curator data");
                System.out.println("创建节点: " + createdPath);
            }
            
            // 读取数据
            String data = example.getData(path);
            System.out.println("节点数据: " + data);
            
            // 修改数据
            Stat stat = example.setData(path, "Updated with Curator");
            System.out.println("修改后的数据版本: " + stat.getVersion());
            
            // 添加监听器
            example.watchNode(path);
            
            // 创建子节点
            String childPath = path + "/child";
            example.createNode(childPath, "Child data");
            
            // 获取子节点
            List<String> children = example.getChildren(path);
            System.out.println("子节点列表: " + children);
            
            // 再次修改数据以触发监听器
            System.out.println("修改数据以触发监听器...");
            example.setData(path, "Triggered watcher");
            
            // 等待一下以便看到监听器效果
            Thread.sleep(2000);
            
            // 删除节点 (会级联删除子节点)
            example.deleteNode(path);
            System.out.println("节点已删除");
            
        } catch (Exception e) {
            System.err.println("发生错误: " + e.getMessage());
            e.printStackTrace();
        } finally {
            example.close();
        }
    }
} 